<script setup>
import { ref, onMounted, nextTick, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { VideoCamera, StarFilled } from '@element-plus/icons-vue'
import { getMovie, pageMovies } from '@/api/movies'
import dayjs from 'dayjs'
import { checkSave, addSave, deleteSaveByMovie } from '@/api/save'
import { buyTicket } from '@/api/ticket'
import { pageCommentsByMovie, createComment } from '@/api/comment'

const route = useRoute()
const router = useRouter()

const movie = ref(null)
const loading = ref(true)
const hotList = ref([])
const isSaved = ref(false)

// 购票弹窗
const buyVisible = ref(false)
const buyQty = ref(1)
const submitting = ref(false)

const fetchDetail = async (id) => {
  loading.value = true
  try {
    const res = await getMovie(id)
    if (res.code === '200') {
      movie.value = res.data || null
    } else {
      ElMessage.error(res.msg || '获取详情失败')
    }
  } catch (e) {
    // 已由拦截器统一提示
  } finally {
    loading.value = false
  }
}

const fetchHot = async () => {
  try {
    const res = await pageMovies({ status: 'HOT', pageNo: 1, pageSize: 8 })
    if (res.code === '200') {
      hotList.value = res.data?.records || []
    }
  } catch {}
}

const checkSaved = async (mid) => {
  const token = localStorage.getItem('token')
  if (!token) { isSaved.value = false; return }
  try {
    const res = await checkSave(Number(mid))
    if (res.code === '200') {
      isSaved.value = !!res.data
    }
  } catch {}
}

const onToggleSave = async () => {
  const id = route.params.id
  const token = localStorage.getItem('token')
  if (!token) { ElMessage.info('请先登录后再收藏'); router.push('/login'); return }
  try {
    if (!isSaved.value) {
      const res = await addSave({ mid: Number(id), mname: movie.value?.mname || movie.value?.title })
      if (res.code === '200') {
        isSaved.value = true
        ElMessage.success(res.msg || '收藏成功')
      } else if (res.code === '300') {
        isSaved.value = true
        ElMessage.info(res.msg || '已收藏')
      } else {
        ElMessage.error(res.msg || '收藏失败')
      }
    } else {
      const res = await deleteSaveByMovie(Number(id))
      if (res.code === '200') {
        isSaved.value = false
        ElMessage.success(res.msg || '已取消收藏')
      } else {
        ElMessage.error(res.msg || '取消失败')
      }
    }
  } catch {}
}

onMounted(() => {
  const id = route.params.id
  if (!id) {
    ElMessage.error('缺少电影ID')
    router.replace('/')
    return
  }
  fetchDetail(id)
  fetchHot()
  checkSaved(id)
  loadComments()
})

// 监听路由参数变化，切换热门推荐时刷新详情与评论
watch(() => route.params.id, (id, oldId) => {
  if (!id || id === oldId) return
  isSaved.value = false
  fetchDetail(id)
  checkSaved(id)
  cPageNo.value = 1
  loadComments()
  nextTick(() => window.scrollTo({ top: 0, behavior: 'smooth' }))
})
const scoreText = (s) => {
  if (!s && s !== 0) return '暂无评分'
  return typeof s === 'number' && s.toFixed ? s.toFixed(1) : s
}

const goHome = () => router.push('/')
const goDetail = (id) => router.push(`/movie/${id}`)
const cleanUrl = (url) => (url ? String(url).replace(/`/g, '').trim() : '')
const posterSrc = (obj) => cleanUrl(obj?.posterUrl) || obj?.imageUrl || ''

const onBuy = () => {
  const token = localStorage.getItem('token')
  if (!token) { ElMessage.info('请先登录后再购票'); router.push('/login'); return }
  buyQty.value = 1
  buyVisible.value = true
}

const submitBuy = async () => {
  if (!movie.value) return
  const id = Number(route.params.id)
  const unitPrice = Number(movie.value.price || 0)
  if (!unitPrice || unitPrice <= 0) { ElMessage.error('该电影暂未设置票价'); return }
  if (buyQty.value <= 0) { ElMessage.error('购买数量必须大于0'); return }
  submitting.value = true
  try {
    const res = await buyTicket({ mid: id, mname: movie.value.mname || movie.value.title, unitPrice, quantity: buyQty.value, note: '' })
    if (res.code === '200') {
      ElMessage.success(res.msg || '购票成功，已生成订单')
      buyVisible.value = false
      router.push('/me/orders')
    } else {
      ElMessage.error(res.msg || '购票失败')
    }
  } catch (e) {
    // 已由拦截器统一提示
  } finally {
    submitting.value = false
  }
}
// 评论相关
const comments = ref([])
const commentsLoading = ref(false)
const cPageNo = ref(1)
const cPageSize = ref(5)
const cTotal = ref(0)
const minScore = ref(null)

const commentVisible = ref(false)
const commentScore = ref(8.0)
const commentContent = ref('')
const commentSubmitting = ref(false)

// 简易富文本编辑器（禁止图片/视频），使用 execCommand
const commentEditor = ref(null)
const format = (cmd) => document.execCommand(cmd, false)
const formatBlock = (block) => document.execCommand('formatBlock', false, block)
const insertList = (cmd) => document.execCommand(cmd, false)
const createLink = () => {
  const url = window.prompt('输入链接地址（http/https）：', 'https://')
  if (!url) return
  if (!/^https?:\/\//i.test(url)) { ElMessage.error('仅允许 http/https 链接'); return }
  document.execCommand('createLink', false, url)
}
const clearFormats = () => {
  if (commentEditor.value) {
    const text = commentEditor.value.innerText || ''
    const lines = text.split('\n').map(l => `<p>${l.replace(/\s+/g,' ').trim()}</p>`).join('')
    commentEditor.value.innerHTML = lines
    commentContent.value = commentEditor.value.innerHTML
  }
}
const onPastePlain = (e) => {
  const text = (e.clipboardData || window.clipboardData).getData('text/plain')
  document.execCommand('insertText', false, text)
}
const onDropPrevent = () => {}

// 处理中文输入法组合，避免 caret 跳动
const composing = ref(false)
const onCommentInput = (e) => { if (composing.value) return; commentContent.value = e.target.innerHTML }
const onCommentCompStart = () => { composing.value = true }
const onCommentCompEnd = (e) => { composing.value = false; commentContent.value = e.target.innerHTML }

const sanitizeHtml = (html) => {
  if (!html) return ''
  const parser = new DOMParser()
  const doc = parser.parseFromString(String(html), 'text/html')
  const allowed = new Set(['p','br','b','i','u','strong','em','span','a','ul','ol','li','blockquote','code','pre','h1','h2','h3','h4'])
  const walk = (node) => {
    const children = Array.from(node.childNodes)
    for (const child of children) {
      if (child.nodeType === 1) {
        const tag = child.tagName.toLowerCase()
        if (!allowed.has(tag)) {
          // unwrap disallowed tags (e.g. img, video, iframe, audio)
          while (child.firstChild) node.insertBefore(child.firstChild, child)
          node.removeChild(child)
          continue
        }
        const attrs = Array.from(child.attributes || [])
        for (const attr of attrs) {
          const name = attr.name.toLowerCase()
          const isEvent = name.startsWith('on')
          const isDanger = ['style','src','data','xlink:href'].includes(name)
          if (isEvent || isDanger || (child.tagName.toLowerCase() !== 'a' && name !== 'href')) {
            child.removeAttribute(name)
          }
        }
        if (tag === 'a') {
          let href = child.getAttribute('href') || ''
          if (!/^https?:\/\//i.test(href)) child.removeAttribute('href')
        }
        walk(child)
      }
    }
  }
  walk(doc.body)
  return doc.body.innerHTML
}

const loadComments = async () => {
  const id = Number(route.params.id)
  if (!id) return
  commentsLoading.value = true
  try {
    const res = await pageCommentsByMovie({ mid: id, pageNo: cPageNo.value, pageSize: cPageSize.value, minScore: minScore.value ?? undefined })
    if (res.code === '200') {
      comments.value = res.data?.records || []
      cTotal.value = res.data?.total || 0
    }
  } catch (e) {} finally {
    commentsLoading.value = false
  }
}

const openCommentDialog = () => {
  const token = localStorage.getItem('token')
  if (!token) { ElMessage.info('请先登录后再评论'); router.push('/login'); return }
  commentScore.value = 8.0
  commentContent.value = ''
  commentVisible.value = true
  nextTick(() => { if (commentEditor.value) commentEditor.value.innerHTML = '' })
}

const submitComment = async () => {
  if (!movie.value) return
  const plain = String(commentContent.value || '').replace(/<[^>]+>/g, '').trim()
  if (!plain) { ElMessage.error('评论内容不能为空'); return }
  const id = Number(route.params.id)
  commentSubmitting.value = true
  try {
    const res = await createComment({ mid: id, mname: movie.value.mname || movie.value.title, score: Number(commentScore.value), content: sanitizeHtml(commentContent.value) })
    if (res.code === '200') {
      ElMessage.success(res.msg || '发布成功')
      commentVisible.value = false
      // 刷新评论列表
      cPageNo.value = 1
      await loadComments()
    } else {
      ElMessage.error(res.msg || '发布失败')
    }
  } catch (e) {} finally {
    commentSubmitting.value = false
  }
}
</script>

<template>
  <div class="detail-page">
    <!-- 顶部导航 -->
    <div class="nav">
      <div class="brand">
        <el-icon size="22" class="brand-icon"><VideoCamera /></el-icon>
        <span class="brand-title">电影详细信息</span>
      </div>
      <div class="actions">
        <el-link type="primary" @click="goHome">返回首页</el-link>
      </div>
    </div>

    <!-- 海报英雄区 -->
    <section class="hero" v-if="movie">
      <div class="hero-bg">
        <img :src="posterSrc(movie)" alt="poster" />
        <div class="mask" />
      </div>
      <div class="hero-content glass">
        <div class="poster">
          <img :src="posterSrc(movie)" alt="poster" />
        </div>
        <div class="meta">
          <h1 class="title">{{ movie.mname || movie.title }}</h1>
          <div class="sub">
            <span>{{ movie.type || '电影' }}</span>
            <span v-if="movie.mtime">· {{ movie.mtime }} 分钟</span>
            <span v-if="movie.mdate">· 上映 {{ dayjs(movie.mdate).format('YYYY-MM-DD') }}</span>
            <span v-if="movie.status">· {{ movie.status }}</span>
            <span v-if="movie.price">· ￥{{ movie.price }}</span>
          </div>
          <div class="rating" v-if="movie.rating || movie.score">
            <el-icon class="star"><StarFilled /></el-icon>
            <span>{{ scoreText(movie.rating || movie.score) }}</span>
          </div>
          <div class="actions-line">
            <el-button type="primary" @click="onBuy">购票</el-button>
            <el-button :type="isSaved ? 'success' : 'default'" @click="onToggleSave">{{ isSaved ? '已收藏' : '收藏' }}</el-button>
            <el-button>分享</el-button>
          </div>
        </div>
      </div>
    </section>

    <!-- 简介 -->
    <section class="section">
      <div class="section-header">
        <h2>剧情简介</h2>
      </div>
      <div class="desc" v-if="movie">
        <div v-if="movie.description" v-html="movie.description" />
        <div v-else>暂无简介</div>
      </div>
    </section>

    <!-- 用户评论 -->
    <section class="section">
      <div class="section-header" style="display:flex;align-items:center;gap:12px;">
        <h2>用户评论</h2>
        <div class="comment-actions">
          <el-button type="primary" @click="openCommentDialog">发布评论</el-button>
          <el-select v-model="minScore" placeholder="评分筛选" clearable style="width: 120px;" @change="cPageNo=1;loadComments()">
            <el-option :value="null" label="全部" />
            <el-option :value="6" label="≥ 6" />
            <el-option :value="8" label="≥ 8" />
            <el-option :value="9" label="≥ 9" />
          </el-select>
        </div>
      </div>

      <div v-loading="commentsLoading" class="comments">
        <template v-if="comments.length">
          <el-card v-for="(c, idx) in comments" :key="c.id || idx" class="comment-card" shadow="hover">
            <div class="row1">
              <div class="uname">{{ c.uname || '匿名用户' }}</div>
              <div class="score">评分：{{ c.score }}</div>
              <div class="time">{{ dayjs(c.cotime || c.createdAt).format('YYYY-MM-DD HH:mm') }}</div>
            </div>
            <div class="content" v-html="sanitizeHtml(c.content)" />
          </el-card>
          <div class="pager">
            <el-pagination
              background
              layout="prev, pager, next"
              :total="cTotal"
              :page-size="cPageSize"
              :current-page="cPageNo"
              @current-change="(p)=>{ cPageNo = p; loadComments(); }"
            />
          </div>
        </template>
        <template v-else>
          <div class="empty">暂无评论，快来抢沙发吧~</div>
        </template>
      </div>
    </section>

    <!-- 热门推荐 -->
    <section class="section">
      <div class="section-header">
        <h2>热门推荐</h2>
      </div>
      <div class="grid">
        <el-card
          v-for="(m, i) in hotList"
          :key="m.id || i"
          class="card clickable"
          shadow="hover"
          @click="m.id && goDetail(m.id)"
        >
          <div class="poster-sm">
            <img :src="posterSrc(m) || posterSrc(movie)" :alt="m.mname || m.title" />
          </div>
          <div class="info">
            <div class="name">{{ m.mname || m.title }}</div>
            <div class="meta-row">
              <span class="type">{{ m.type || '电影' }}</span>
              <span class="rating" v-if="(m.rating || m.score)">
                <el-icon class="star"><StarFilled /></el-icon>
                {{ scoreText(m.rating || m.score) }}
              </span>
            </div>
          </div>
        </el-card>
      </div>
    </section>

    <!-- 购票弹窗 -->
    <el-dialog v-model="buyVisible" title="购票" width="420px" :close-on-click-modal="false">
      <div class="buy-dialog">
        <div class="row">
          <div class="label">影片</div>
          <div class="value">{{ movie?.mname || movie?.title }}</div>
        </div>
        <div class="row">
          <div class="label">单价</div>
          <div class="value">￥{{ movie?.price || 0 }}</div>
        </div>
        <div class="row">
          <div class="label">数量</div>
          <div class="value">
            <el-input-number v-model="buyQty" :min="1" :max="20" />
          </div>
        </div>
        <div class="row total">
          <div class="label">合计</div>
          <div class="value">￥{{ (Number(movie?.price || 0) * buyQty).toFixed(2) }}</div>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="buyVisible = false">取消</el-button>
          <el-button type="primary" :loading="submitting" @click="submitBuy">确认购票</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 评论发布弹窗 -->
    <el-dialog v-model="commentVisible" title="发布评论" width="520px" :close-on-click-modal="false">
      <div class="buy-dialog">
        <div class="row">
          <div class="label">影片</div>
          <div class="value">{{ movie?.mname || movie?.title }}</div>
        </div>
        <div class="row">
          <div class="label">评分</div>
          <div class="value">
            <el-input-number v-model="commentScore" :min="0" :max="10" :step="0.5" />
          </div>
        </div>
        <div class="row">
          <div class="label">内容</div>
          <div class="value">
            <div class="toolbar">
              <el-button size="small" @click="format('bold')">加粗</el-button>
              <el-button size="small" @click="format('italic')">斜体</el-button>
              <el-button size="small" @click="format('underline')">下划线</el-button>
              <el-button size="small" @click="formatBlock('blockquote')">引用</el-button>
              <el-button size="small" @click="formatBlock('p')">段落</el-button>
              <el-button size="small" @click="insertList('insertUnorderedList')">• 列表</el-button>
              <el-button size="small" @click="insertList('insertOrderedList')">1. 列表</el-button>
              <el-button size="small" @click="createLink()">链接</el-button>
              <el-button size="small" @click="clearFormats()">清除样式</el-button>
            </div>
            <div
               ref="commentEditor"
               class="editor"
               contenteditable="true"
               @input="onCommentInput"
               @compositionstart="onCommentCompStart"
               @compositionend="onCommentCompEnd"
               @paste.prevent="onPastePlain"
               @drop.prevent="onDropPrevent"
             ></div>
          </div>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="commentVisible = false">取消</el-button>
          <el-button type="primary" :loading="commentSubmitting" @click="submitComment">发布</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
.detail-page {
  min-height: 100vh;
  background:
    radial-gradient(1200px 600px at 15% 20%, #101317 0%, #0b0e12 40%, #06080b 100%),
    linear-gradient(180deg, #0b0f15 0%, #0d1117 100%);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
}
.brand { display: flex; align-items: center; gap: 8px; color: #e5eaf3; }
.brand-icon { color: #ffd04b; }
.brand-title { font-weight: 600; letter-spacing: .5px; }
.actions :deep(.el-link) { margin-left: 12px; }

.hero { position: relative; padding: 12px 24px 0; }
.hero-bg { position: relative; height: 340px; border-radius: 12px; overflow: hidden; }
.hero-bg img { width: 100%; height: 100%; object-fit: cover; display: block; filter: brightness(.85); }
.hero-bg .mask { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,.55) 100%); }

.glass {
  position: relative; margin-top: -80px; display: grid; grid-template-columns: 180px 1fr; gap: 18px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 12px;
  padding: 16px;
  backdrop-filter: blur(8px);
}
.poster img { width: 180px; height: 260px; object-fit: cover; border-radius: 8px; display: block; }
.meta { color: #e5eaf3; }
.title { margin: 0; font-size: 24px; font-weight: 600; }
.sub { margin-top: 6px; color: #cfd3dc; }
.rating { margin-top: 8px; display: inline-flex; align-items: center; gap: 6px; color: #ffd04b; }
.actions-line { margin-top: 10px; display: flex; gap: 10px; }

.section { padding: 18px 24px 28px; }
.section-header h2 { margin: 0 0 10px; color: #e5eaf3; }
.desc { color: #cfd3dc; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); border-radius: 12px; padding: 12px; }

.grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
@media (max-width: 1200px) { .grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 900px) { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .grid { grid-template-columns: 1fr; } }

.card :deep(.el-card__body) { padding: 0; overflow: hidden; }
.poster-sm img { width: 100%; height: 200px; object-fit: cover; display: block; }
.info { padding: 10px 12px; }
.name { font-weight: 600; color: #1f2b38; }
.meta-row { margin-top: 4px; display: flex; align-items: center; gap: 8px; color: #606266; }
.star { color: #ffd04b; margin-right: 2px; }
.clickable { cursor: pointer; }

.buy-dialog { padding: 6px 2px; color: #1f2b38; }
.row { display: flex; align-items: center; padding: 6px 0; }
.row .label { width: 80px; color: #606266; }
.row .value { flex: 1; }
.row.total .value { font-weight: 600; color: #1f2b38; }

/* 富文本编辑器样式 */
.toolbar { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.editor { min-height: 140px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 8px; background: #fff; overflow: auto; white-space: pre-wrap; }
.editor:empty:before { content: '在此编辑你的评论…'; color: #c0c4cc; }
.editor p { margin: 0 0 8px; }
.editor ul, .editor ol { padding-left: 20px; margin: 0 0 8px; list-style-position: outside; }
.editor blockquote { margin: 0 0 8px; padding-left: 10px; border-left: 3px solid #ebeef5; color: #606266; }


.comment-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.comments { display: flex; flex-direction: column; gap: 10px; }
.comment-card :deep(.el-card__body) { padding: 10px 12px; }
.row1 { display: flex; gap: 12px; align-items: center; color: #606266; }
.row1 .uname { font-weight: 600; color: #1f2b38; }
.row1 .time { margin-left: auto; }
.content { margin-top: 6px; color: #1f2b38; }
.pager { display: flex; justify-content: center; margin-top: 8px; }
.empty { color: #cfd3dc; }
</style>